﻿using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Linq;
using System.Text;
using System.Web.Mvc;
using Catalyst.Mvc.Extensions;
using Trirand.Web.Mvc;
using System.Web;
using System.Web.Routing;

namespace Catalyst.Mvc
{
	public delegate JsonResult DataMethod();
	public delegate ActionResult EditMethod();

	public delegate JsonResult ChildDataMethod(string parentRowID);
	public delegate ActionResult ChildEditMethod(string parentRowID);

	public abstract partial class LiteGrid<TGrid> : JQGrid
		where TGrid : LiteGrid<TGrid>, new()
	{
		public List<ColumnDependency> ColumnDependencies { get; private set; }
		internal string ParentGridID { get; set; }

		public LiteGrid()
		{
			AddDialogSettings.CloseAfterAdding = true;
			AddDialogSettings.ReloadAfterSubmit = true;

			EditDialogSettings.CloseAfterEditing = true;
			EditDialogSettings.ReloadAfterSubmit = true;
			ToolBarSettings.ShowRefreshButton = true;

			AppearanceSettings.HighlightRowsOnHover = true;
			AppearanceSettings.ShowRowNumbers = true;
			AppearanceSettings.ShrinkToFit = true;

			RenderingMode = RenderingMode.Default;

			PagerSettings.PageSizeOptions = "[]";

			ColumnDependencies = new List<ColumnDependency>();
		}

		//public TGrid AsParentEditGrid(string ID, string dataUrl, string editUrl, string childGridID)
		//{
		//    return asEditGrid(ID, dataUrl, editUrl, HierarchyMode.Parent, null, childGridID);
		//}

		//public TGrid AsChildEditGrid(string ID, string dataUrl, string editUrl, string parentGridID)
		//{
		//    return asEditGrid(ID, dataUrl, editUrl, HierarchyMode.Child, parentGridID, null);
		//}

		//public TGrid AsParentAndChildEditGrid(string ID, string dataUrl, string editUrl, string parentGridID, string childGridID)
		//{
		//    return asEditGrid(ID, dataUrl, editUrl, HierarchyMode.ParentAndChild, parentGridID, childGridID);
		//}

		public TGrid AsParentEditGrid(string ID, string childGridID, DataMethod dataMethod, EditMethod editMethod = null)
		{
			return asEditGrid(ID, dataMethod.Method.Name, ((editMethod != null) ? editMethod.Method.Name : null), HierarchyMode.Parent, null, childGridID);
		}

		public TGrid AsChildEditGrid(string ID, string parentGridID, ChildDataMethod dataMethod, ChildEditMethod editMethod = null)
		{
			return asEditGrid(ID, dataMethod.Method.Name, ((editMethod != null) ? editMethod.Method.Name : null), HierarchyMode.Child, parentGridID, null);
		}

		public TGrid AsParentAndChildEditGrid(string ID, string parentGridID, string childGridID, ChildDataMethod dataMethod, ChildEditMethod editMethod = null)
		{
			return asEditGrid(ID, dataMethod.Method.Name, ((editMethod != null) ? editMethod.Method.Name : null), HierarchyMode.ParentAndChild, parentGridID, childGridID);
		}

		public TGrid AsEditGrid(string ID, DataMethod dataMethod, EditMethod editMethod)
		{
			return asEditGrid(ID, dataMethod.Method.Name, editMethod.Method.Name, HierarchyMode.None, "", null);
		}

		private TGrid asEditGrid(string ID, string dataUrl, string editUrl, HierarchyMode hierarchyMode, string parentGridID, string childGridID)
		{
			TGrid editGrid = asStandardGrid(ID, dataUrl, editUrl, hierarchyMode, parentGridID, childGridID);

			editGrid.Columns.Add(new JQGridColumn
			{
				DataField = "Edit",
				HeaderText = "&nbsp",
				Width = 100,
				Searchable = false
			});

			editGrid.ClientSideOnDocumentReady = String.Format("addNewButton('{0}', '{0}_pager');\r\n", editGrid.ID);

			this.ToolBarSettings.ShowAddButton = false;
			this.ToolBarSettings.ShowDeleteButton = false;
			this.ToolBarSettings.ShowEditButton = false;

			return editGrid;
		}

		//public TGrid AsParentGrid(string ID, string dataUrl, string editUrl, string childGridID)
		//{
		//    return asStandardGrid(ID, dataUrl, editUrl, HierarchyMode.Parent, null, childGridID);
		//}

		//public TGrid AsChildGrid(string ID, string dataUrl, string editUrl, string parentGridID)
		//{
		//    return asStandardGrid(ID, dataUrl, editUrl, HierarchyMode.Child, parentGridID, null);
		//}

		//public TGrid AsParentAndChildGrid(string ID, string dataUrl, string editUrl, string parentGridID, string childGridID)
		//{
		//    return asStandardGrid(ID, dataUrl, editUrl, HierarchyMode.ParentAndChild, parentGridID, childGridID);
		//}

		public TGrid AsParentGrid(string ID, string childGridID, DataMethod dataMethod, EditMethod editMethod = null)
		{
			return asStandardGrid(ID, dataMethod.Method.Name, ((editMethod != null) ? editMethod.Method.Name : null), HierarchyMode.Parent, null, childGridID);
		}

		public TGrid AsChildGrid(string ID, string parentGridID, ChildDataMethod dataMethod, ChildEditMethod editMethod = null)
		{
			return asStandardGrid(ID, dataMethod.Method.Name, ((editMethod != null) ? editMethod.Method.Name : null), HierarchyMode.Child, parentGridID, null);
		}

		public TGrid AsParentAndChildGrid(string ID, string parentGridID, string childGridID, ChildDataMethod dataMethod, ChildEditMethod editMethod = null)
		{
			return asStandardGrid(ID, dataMethod.Method.Name, ((editMethod != null) ? editMethod.Method.Name : null), HierarchyMode.ParentAndChild, parentGridID, childGridID);
		}

		//public TGrid AsStandardGrid(string ID, string dataUrl)
		//{
		//    return asStandardGrid(ID, dataUrl, null, HierarchyMode.None, null, null);
		//}

		//public TGrid AsStandardGrid(string ID, string dataUrl, string editUrl)
		//{
		//    return asStandardGrid(ID, dataUrl, editUrl, HierarchyMode.None, null, null);
		//}

		public TGrid AsStandardGrid(string ID, DataMethod dataMethod, EditMethod editMethod = null)
		{
			return asStandardGrid(ID, dataMethod.Method.Name, ((editMethod != null) ? editMethod.Method.Name : null), HierarchyMode.None, null, null);
		}

		private TGrid asStandardGrid(string ID, string dataUrl, string editUrl, HierarchyMode hierarchyMode, string parentGridID, string childGridID)
		{
			this.ID = ID;
			this.DataUrl = dataUrl;

			if (!String.IsNullOrEmpty(editUrl))
			{
				this.EditUrl = editUrl;

				this.ToolBarSettings.ShowAddButton = true;
				this.ToolBarSettings.ShowDeleteButton = true;
				this.ToolBarSettings.ShowEditButton = true;
			}

			Action<JQGridColumn> makeColumnsUnsearchable = (c) =>
			{
				c.Searchable = false;
			};

			this.Columns.ForEach(makeColumnsUnsearchable);

			setupHierarchy(hierarchyMode, parentGridID, childGridID);

			return (TGrid)this;
		}

		public void setupHierarchy(HierarchyMode hierarchyMode, string parentGridID, string childGridID)
		{
			this.HierarchySettings.HierarchyMode = hierarchyMode;

			if (hierarchyMode == HierarchyMode.Parent || hierarchyMode == HierarchyMode.None)
			{
				this.AppendToGridInitializedScripts("initEditGrid('" + this.ID + "');");
			}
			else
			{
				this.ParentGridID = parentGridID;

				this.AppendToGridInitializedScripts("initChildEditGrids('" + parentGridID + "');");
			}

			if (hierarchyMode == HierarchyMode.Parent || hierarchyMode == HierarchyMode.ParentAndChild)
			{
				StringBuilder sb = new StringBuilder();
				sb.AppendLine("function(subgrid_id, row_id, message, suffix) { ");
				sb.AppendLine(" showSubGrid_" + childGridID + "(subgrid_id, row_id);");
				sb.AppendLine("	showSubGridAddNewButton(subgrid_id);");
				sb.AppendLine("}");

				this.ClientSideEvents.SubGridRowExpanded = sb.ToString();
			}
		}

		public delegate TDataItem EditItemLoader<TDataItem>(string rowKey);

		public delegate void EditFunction<TDataItem>(TDataItem dataItem, NameValueCollection rowData) where TDataItem : class;

		public ActionResult Edit<TDataItem>(EditFunction<TDataItem> edit, EditItemLoader<TDataItem> loadEditItem, Action<string> delete)
			where TDataItem : class, new()
		{
			try
			{
				JQGridEditData editData = GetEditData();

				switch (AjaxCallBackMode)
				{
					case AjaxCallBackMode.EditRow: edit.Invoke(loadEditItem.Invoke(editData.RowKey), editData.RowData); break;
					case AjaxCallBackMode.AddRow: edit.Invoke(new TDataItem(), editData.RowData); break;
					case AjaxCallBackMode.DeleteRow: delete.Invoke(editData.RowKey); break;
					default: break;
				}

				return RedirectToDataRequest();
			}
			catch (Exception ex)
			{
				return this.ShowEditValidationMessage(ex.Message);
			}
		}

		public RedirectResult RedirectToDataRequest()
		{
			HttpContextWrapper httpContextBase = new HttpContextWrapper(HttpContext.Current);
			RequestContext requestContext = new RequestContext(httpContextBase, getRouteData());

			return new RedirectResult(new UrlHelper(requestContext).Action(this.DataUrl, getCurrentControllerName()));
		}

		private string getCurrentControllerName()
		{
			return getRouteData().Values["controller"].ToString();
		}

		private RouteData getRouteData()
		{
			return RouteTable.Routes.GetRouteData(new HttpContextWrapper(HttpContext.Current));
		}
	}
}
